package com.coderly.onlinegallerysharingplatform.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.coderly.onlinegallerysharingplatform.common.convention.errorcode.ErrorCode;
import com.coderly.onlinegallerysharingplatform.common.convention.exception.BizException;
import com.coderly.onlinegallerysharingplatform.common.response.Response;
import com.coderly.onlinegallerysharingplatform.enums.SpaceLevelEnum;
import com.coderly.onlinegallerysharingplatform.enums.SpaceRoleEnum;
import com.coderly.onlinegallerysharingplatform.enums.SpaceTypeEnum;
import com.coderly.onlinegallerysharingplatform.model.dao.entity.SpaceDO;
import com.coderly.onlinegallerysharingplatform.model.dao.entity.SpaceUserDO;
import com.coderly.onlinegallerysharingplatform.model.dao.entity.UserDO;
import com.coderly.onlinegallerysharingplatform.model.dto.req.space.CreateSpaceReqDTO;
import com.coderly.onlinegallerysharingplatform.model.dto.req.space.DeleteSpaceReqDTO;
import com.coderly.onlinegallerysharingplatform.model.dto.req.space.EditSpaceReqDTO;
import com.coderly.onlinegallerysharingplatform.model.dto.req.space.QuerySpaceReqDTO;
import com.coderly.onlinegallerysharingplatform.model.dto.resp.space.SpaceRespDTO;
import com.coderly.onlinegallerysharingplatform.model.dto.resp.user.UserRespDTO;
import com.coderly.onlinegallerysharingplatform.service.SpaceService;
import com.coderly.onlinegallerysharingplatform.model.dao.mapper.SpaceMapper;
import com.coderly.onlinegallerysharingplatform.service.SpaceUserService;
import com.coderly.onlinegallerysharingplatform.service.UserService;
import com.coderly.onlinegallerysharingplatform.toolkit.ExceptionTrowUtils;
import com.coderly.onlinegallerysharingplatform.toolkit.UserUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.support.TransactionTemplate;

import javax.annotation.Resource;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
* @author 26788
* @description 针对表【t_space(空间)】的数据库操作Service实现
* @createDate 2025-03-11 20:17:23
*/
@Slf4j
@Service
public class SpaceServiceImpl extends ServiceImpl<SpaceMapper, SpaceDO>
    implements SpaceService {

    @Resource
    private UserService userService;
    private static final List<String> ALLOWED_SORT_FIELDS = List.of("id", "user_id", "space_name", "space_level");
    private static final String DEFAULT_SORT_ORDER = "ascend";
    @Resource
    private TransactionTemplate transactionTemplate;
    @Resource
    private SpaceUserService spaceUserService;

    /**
     * 检验空间
     */
    @Override
    public void validSpace(SpaceDO spaceDO, boolean isAdd) {
        // 参数基础校验
        ExceptionTrowUtils.throwIf(spaceDO == null, ErrorCode.PARAMS_ERROR);

        // 使用常量管理长度限制
        final int MAX_SPACE_NAME_LENGTH = 25;

        // 提取关键字段
        String spaceName = spaceDO.getSpaceName();
        Integer spaceLevel = spaceDO.getSpaceLevel();
        Integer spaceType = spaceDO.getSpaceType();

        // 新增操作专属校验
        if (isAdd) {
            // 使用卫语句减少嵌套层级
            ExceptionTrowUtils.throwIf(StrUtil.isBlank(spaceName),
                    ErrorCode.PARAMS_ERROR, "空间名称不能为空");
            ExceptionTrowUtils.throwIf(spaceLevel == null,
                    ErrorCode.PARAMS_ERROR, "空间级别不能为空");
            ExceptionTrowUtils.throwIf(spaceType == null,
                    ErrorCode.PARAMS_ERROR, "空间类型不能为空");
        }

        // 名称长度校验（通用规则）
        if (StrUtil.isNotBlank(spaceName) && spaceName.length() > MAX_SPACE_NAME_LENGTH) {
            throw new BizException(ErrorCode.PARAMS_ERROR,
                    "空间名称不能超过" + MAX_SPACE_NAME_LENGTH + "个字符");
        }

        // 空间级别有效性校验（通用规则）
        if (spaceLevel != null) {
            SpaceLevelEnum spaceLevelEnum = SpaceLevelEnum.getEnumByValue(spaceLevel);
            ExceptionTrowUtils.throwIf(spaceLevelEnum == null,
                    ErrorCode.PARAMS_ERROR, "不存在的空间级别:" + spaceLevel);
        }
        if (spaceType != null) {
            SpaceTypeEnum spaceTypeEnum = SpaceTypeEnum.getEnumByValue(spaceType);
            ExceptionTrowUtils.throwIf(spaceTypeEnum == null,
                    ErrorCode.PARAMS_ERROR, "不存在的空间类型:" + spaceType);
        }
    }


    /**
     * 实体类转包装响应类
     */
    @Override
    public SpaceRespDTO getSpaceRespDTO(SpaceDO spaceDO) {
        // 基础对象转换（防御空对象）
        SpaceRespDTO dto = Optional.ofNullable(spaceDO)
                .map(SpaceRespDTO::obj2RespDTO)
                .orElseThrow(() -> new BizException(ErrorCode.PARAMS_ERROR, "空间数据不能为空"));

        // 用户信息处理管道
        Optional.ofNullable(spaceDO)
                .map(SpaceDO::getUserId)
                .filter(userId -> userId > 0)  // 有效ID过滤
                .ifPresent(userId -> {
                    // 用户查询与转换（带空值保护）
                    UserRespDTO userDto = Optional.ofNullable(userService.getById(userId))
                            .map(UserRespDTO::obj2RespDTO)
                            .orElseGet(() -> {
                                log.warn("用户信息缺失 user_id:{}", userId);
                                return null;  // 或返回默认匿名用户
                            });
                    dto.setUser(userDto);
                });

        return dto;
    }
    /**
     * 实体类转包装响应类（分页）
     */
    @Override
    public Page<SpaceRespDTO> getSpaceRespDTOPage(Page<SpaceDO> spaceDOPage) {
        // 创建分页结果对象（保持原始分页参数）
        Page<SpaceRespDTO> resultPage = new Page<>(
                spaceDOPage.getCurrent(),
                spaceDOPage.getSize(),
                spaceDOPage.getTotal()
        );

        // 空数据快速返回
        List<SpaceDO> originList = spaceDOPage.getRecords();
        if (CollUtil.isEmpty(originList)) {
            return resultPage;
        }

        // 基础对象转换（DO -> DTO）
        List<SpaceRespDTO> resultList = originList.stream()
                .map(SpaceRespDTO::obj2RespDTO)  // 使用静态转换方法
                .collect(Collectors.toList());

        // 获取关联用户ID集合（自动去重）
        Set<Long> userIds = originList.stream()
                .map(SpaceDO::getUserId)
                .filter(Objects::nonNull)  // 过滤空用户ID
                .collect(Collectors.toSet());

        // 批量获取用户信息（使用ID集合查询）
        Map<Long, UserDO> userMap = userService.listByIds(userIds).stream()
                .collect(Collectors.toMap(
                        UserDO::getId,  // 键：用户ID
                        Function.identity(),  // 值：用户对象本身
                        (existing, replacement) -> existing  // 处理键冲突策略（保留已有）
                ));

        // 填充关联用户信息
        resultList.forEach(dto -> {
            UserDO user = userMap.get(dto.getUserId());
            dto.setUser(Optional.ofNullable(user)
                    .map(UserRespDTO::obj2RespDTO)  // 安全转换
                    .orElse(null));  // 用户不存在时设置为null
        });

        // 设置最终结果集
        resultPage.setRecords(resultList);
        return resultPage;
    }


    /**
     * 构建查询Wrapper
     */

    @Override
    public QueryWrapper<SpaceDO> buildSpaceQueryWrapper(QuerySpaceReqDTO querySpaceReqDTO) {
        QueryWrapper<SpaceDO> queryWrapper = new QueryWrapper<>();
        // 快速返回空查询条件
        if (querySpaceReqDTO == null) {
            return queryWrapper;
        }

        // 使用链式操作提升可读性
        queryWrapper
                .eq(querySpaceReqDTO.getId() != null, "id", querySpaceReqDTO.getId())
                .eq(querySpaceReqDTO.getUserId() != null, "user_id", querySpaceReqDTO.getUserId())
                .eq(querySpaceReqDTO.getSpaceLevel() != null, "space_level", querySpaceReqDTO.getSpaceLevel())
                .eq(querySpaceReqDTO.getSpaceType() != null, "space_type", querySpaceReqDTO.getSpaceType())
                .like(StrUtil.isNotBlank(querySpaceReqDTO.getSpaceName()),
                        "space_name", querySpaceReqDTO.getSpaceName());

        // 独立处理排序逻辑
        processSortCondition(queryWrapper,
                querySpaceReqDTO.getSortField(),
                querySpaceReqDTO.getSortOrder());

        return queryWrapper;
    }


    /**
     * 处理排序条件（安全校验+方向判断）
     */
    private void processSortCondition(QueryWrapper<SpaceDO> queryWrapper,
                                      String sortField,
                                      String sortOrder) {
        // 校验排序字段合法性
        if (!isValidSortField(sortField)) {
            return;
        }

        // 安全处理排序方向
        boolean isAsc = DEFAULT_SORT_ORDER.equalsIgnoreCase(
                Optional.ofNullable(sortOrder).orElse("")
        );
        queryWrapper.orderBy(true, isAsc, sortField);
    }

    /**
     * 校验排序字段是否合法（防御SQL注入）
     */
    private boolean isValidSortField(String sortField) {
        return StrUtil.isNotBlank(sortField)
                && ALLOWED_SORT_FIELDS.contains(sortField.toLowerCase());
    }

    @Override
    public void fillSpaceDefaultFieldBySpaceLevel(SpaceDO spaceDO) {
        SpaceLevelEnum spaceLevelEnum = SpaceLevelEnum.getEnumByValue(spaceDO.getSpaceLevel());
        if (spaceLevelEnum != null) {
            long maxSize = spaceLevelEnum.getMaxSize();
            // 用户或者管理员未指定maxSize使用默认maxSize
            if (spaceDO.getMaxSize() == null) {
                spaceDO.setMaxSize(maxSize);
            }
            // 用户或者管理员未指定maxCount使用默认maxCount
            long maxCount = spaceLevelEnum.getMaxCount();
            if (spaceDO.getMaxCount() == null) {
                spaceDO.setMaxCount(maxCount);
            }
        }
    }

    /**
     * 创建空间
     * @param createSpaceReqDTO
     * @return
     */
    @Override
    public Long createSpace(CreateSpaceReqDTO createSpaceReqDTO) {
        SpaceDO spaceDO = new SpaceDO();
        BeanUtils.copyProperties(createSpaceReqDTO, spaceDO);
        // 赋默认值
        if (StrUtil.isBlank(spaceDO.getSpaceName())) {
            spaceDO.setSpaceName("默认个人空间");
        }
        if (ObjUtil.isNull(spaceDO.getSpaceLevel())) {
            spaceDO.setSpaceLevel(SpaceLevelEnum.COMMON.getValue());
        }
        if (spaceDO.getSpaceType() == null) {
            spaceDO.setSpaceType(SpaceTypeEnum.PRIVATE.getValue());
        }
        // 填充maxSize和maxCount
        this.fillSpaceDefaultFieldBySpaceLevel(spaceDO);
        // 校验参数
        this.validSpace(spaceDO, true);
        // 校验权限
        Long loginUserID = UserUtil.getLoginUserId();
        spaceDO.setUserId(loginUserID);
        if (SpaceLevelEnum.COMMON.getValue() != spaceDO.getSpaceLevel() && !UserUtil.checkIsAdmin(loginUserID)) {
            throw new BizException(ErrorCode.NO_AUTH_ERROR, "无权限创建该等级空间");
        }
        // TODO，团队空间扩展为创建2个，付费可继续创建
        // 控制同一个用户只能创建一个个人空间，以及一个团队空间
        String lock = String.valueOf(loginUserID).intern();
        synchronized (lock) {
            Long newSpaceId = transactionTemplate.execute(status -> {
                // 判断用户是否已经有个人空间
                boolean exists = this.lambdaQuery().
                        eq(SpaceDO::getUserId, loginUserID)
                        .eq(SpaceDO::getSpaceType, spaceDO.getSpaceType())
                        .exists();
                ExceptionTrowUtils.throwIf(exists, ErrorCode.PARAMS_ERROR, "每位用户仅可开通一个个人空间");
                // 入库
                boolean save = this.save(spaceDO);
                ExceptionTrowUtils.throwIf(!save, ErrorCode.OPERATION_ERROR, "空间创建失败，请稍后再试");
                // 创建成功后，如果是团队空间，关联新增团队成员记录
                if (SpaceTypeEnum.TEAM.getValue() == spaceDO.getSpaceType()) {
                    SpaceUserDO spaceUserDO = new SpaceUserDO();
                    spaceUserDO.setSpaceId(spaceDO.getId());
                    spaceUserDO.setUserId(loginUserID);
                    spaceUserDO.setSpaceRole(SpaceRoleEnum.ADMIN.getValue());
                    save = spaceUserService.save(spaceUserDO);
                    ExceptionTrowUtils.throwIf(!save, ErrorCode.OPERATION_ERROR, "创建成员失败");
                }
                return spaceDO.getId();
            });
            return newSpaceId;
        }
    }

    @Override
    public Response<Boolean> deleteSpace(DeleteSpaceReqDTO deleteSpaceReqDTO) {

        long loginUserId = StpUtil.getLoginIdAsLong();
        long id = deleteSpaceReqDTO.getId();
        // 判断是否存在
        SpaceDO spaceDO = getById(id);
        ExceptionTrowUtils.throwIf(spaceDO == null, ErrorCode.NOT_FOUND_ERROR);
        // 仅本人和管理员可以删除
        if (!spaceDO.getUserId().equals(loginUserId) && !UserUtil.getLoginUserRole().equals("admin")) {
            throw new BizException(ErrorCode.NO_AUTH_ERROR, "无权限删除空间");
        }
        // 操作数据库
        boolean result = this.removeById(id);
        ExceptionTrowUtils.throwIf(!result, ErrorCode.OPERATION_ERROR);
        return Response.success(true);
    }

    @Override
    public Response<Boolean> editSpace(EditSpaceReqDTO editSpaceReqDTO) {
        SpaceDO spaceDO = new SpaceDO();
        BeanUtils.copyProperties(editSpaceReqDTO, spaceDO);
        this.fillSpaceDefaultFieldBySpaceLevel(spaceDO);
        spaceDO.setEditTime(new Date());
        this.validSpace(spaceDO, false);
        Long loginUserID = UserUtil.getLoginUserId();
        Long id = editSpaceReqDTO.getId();
        SpaceDO oldSpace = this.getById(id);
        ExceptionTrowUtils.throwIf(oldSpace == null, ErrorCode.OPERATION_ERROR);
        // 仅本人和管理员可以删除
        if (!spaceDO.getUserId().equals(loginUserID) && !UserUtil.getLoginUserRole().equals("admin")) {
            throw new BizException(ErrorCode.NO_AUTH_ERROR, "无权限删除空间");
        }
        boolean updated = this.updateById(spaceDO);
        ExceptionTrowUtils.throwIf(!updated, ErrorCode.OPERATION_ERROR);
        return Response.success(true);
    }
}




